#include "LZW.h"

using namespace std;

/**
 * \fn LZW::LZW()
 *
 * \brief Default constructor.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
**/
LZW::LZW(){
	InitialCodeSize = 8;							// InitialCodeSize by default
	dictionary = new string[DICTIONARY_MAXSIZE];			
	dictionaryCurrentEntry = 0;		
	
	currentDecodedIndex = 0;
	bitCodeBuffer = 0;
	bitCodeBufferPos = 0;
};

/**
 * \fn LZW::~LZW()
 *
 * \brief Destructor.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
**/
LZW::~LZW(){
	delete [] dictionary;
};

/**
 * \fn void LZW::initializeDictionary()
 *
 * \brief Initializes the dictionary.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
**/
void LZW::initializeDictionary(){
	delete [] dictionary;
	dictionary = new string[DICTIONARY_MAXSIZE];

	int defaultEntryNum = 1 << InitialCodeSize;
	int i;
	for (i=0; i<defaultEntryNum; i++){							
		dictionary[i] = i;
	}
	dictionary[i] = "CC";				//Add Clear Code (CC)	
	i++;
	dictionary[i] = "EOI";				//Add End Of Image Code (EOI)
	dictionaryCurrentEntry = defaultEntryNum+2;
};

/**
 * \fn void LZW::setInitialCodeSize(BYTE CodeSize)
 *
 * \brief Sets an initial code size.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
 *
 * \param CodeSize Code size
 * 				   
**/
void LZW::setInitialCodeSize(BYTE CodeSize){
	InitialCodeSize = CodeSize;
};

/**
 * \fn int LZW::calcMaxNum(int bitNum)
 *
 * \brief Calculates the maximum number that can be rappresented with bitNum bits
 *
 * \author Maksym Rybak
 * \date 17.03.2011
 *
 * \param bitNum Number of bits.
 *
 * \return The calculated maximum number.
**/
int LZW::calcMaxNum(int bitNum){
	int res = 1;
	for (int i = 0; i <bitNum; i++){
		res = res * 2;
	}
	res--;
	return res;
};	

/**
 * \fn void LZW::initializeAllWorkVariables()
 *
 * \brief Initializes all work variables.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
**/
void LZW::initializeAllWorkVariables(){
	initializeDictionary();
	code = 0;
	c = "";
	old = "";
	codesize = (int)InitialCodeSize + 1;
	ClearCode = 1 << InitialCodeSize;
	EOICode = ClearCode+1;		
	restart = true;		
};

/**
 * \fn bool LZW::readGIFDataBlock(BYTE *encodedBlock, int blockSize, BYTE *imageIndices)
 *
 * \brief Reads a GIF data block end decode it.
 *
 * \author Maksym Rybak
 * \date 17.03.2011
 *
 * \param encodedBlock Encoded Data Block
 * \param blockSize The number of bytes inside Encoded Data Block
 * \param imageIndices The buffer where we put decoded Image Indices
 *
 * \return true if it succeeds, false if it fails.
**/
bool LZW::readGIFDataBlock(BYTE *encodedBlock, int blockSize, BYTE *imageIndices){																	
	BYTE ch;		

	for (int i=0; i<blockSize; i++){
		ch = encodedBlock[i];							// Read first encoded byte
		
		int bitProcessed = 0;					
		while (bitProcessed < 8){						// Get one bit at time and build code with curret codesize
			int currentBit = (BYTE)ch & (BYTE)1;
			ch = ch >> 1;		
			bitProcessed++;

			if (currentBit == 1)
				bitCodeBuffer = bitCodeBuffer + (1 << bitCodeBufferPos);		// Update current bitCodeBuffer	
			bitCodeBufferPos++;
			
			if (bitCodeBufferPos == codesize){									// We have next code
				code = bitCodeBuffer;
				if (code == ClearCode && currentDecodedIndex == 0){				// First byte of first Data Block is Clear Code																									
					//cout << "Ho letto il primo codice, Clear Code." << endl;
				}else if (code == ClearCode && currentDecodedIndex > 0){		// We have Clear Code, process succeeding codes as if a new data stream was starting
					//cout << "Ho letto un Clear Code. Resetto tutto." << endl;												
					initializeAllWorkVariables();						
				}else if (code == EOICode){										// We have End Of Image code, end of the image data stream
					//cout << "Ho letto un End Code. Fine del data strema." << currentDecodedIndex << endl;
					return true;
				}else if (restart){												// If it's our first code or we have read CC before						
					c = dictionary[code];										// c <- string table entry for code	
					imageIndices[currentDecodedIndex] = c[0];					// Output c, our decoded byte						
					currentDecodedIndex++;												
					old = c;													// old <- c
					restart = false;												
				}else {
					if (code < dictionaryCurrentEntry){							// Code is in Dictionary 
						c = dictionary[code];									// c <- string table entry for code			
						dictionary[dictionaryCurrentEntry] = old + c[0];		// Add to Dictionary: (old + appended first pixel of c) 							
						dictionaryCurrentEntry++;								
					}else{														// Code isn't in Dictionary
						dictionary[dictionaryCurrentEntry] = old + old[0];		// Add to Dictionary: (old + appended first pixel of old)   
						c = dictionary[dictionaryCurrentEntry];					// c <- new string table entry
						dictionaryCurrentEntry++;
					}

					//Output c, our decoded bytes (pixel indices associated with the current code)
					int strLength = c.length();							
					for (int j=0; j<strLength; j++){
						imageIndices[currentDecodedIndex] = c[j];								
						currentDecodedIndex++;														
					}										
					old = c;													// old <- c
				}									
						
				// If (added-dictionary-entry# = max. for codesize) and (codesize < 12 ) increase codesize by 1
				if ((dictionaryCurrentEntry > calcMaxNum(codesize)) && (codesize < 12)){						
					codesize++;						
				}					

				bitCodeBuffer = 0;
				bitCodeBufferPos = 0;
			}
			
		}			
	};

	return true;
};